﻿using System;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Net;
using KCPProject;
using LuaInterface;

namespace Network
{
    public class KcpChannel
    {
        private Socket mUdpClient;
        private IPEndPoint mSvrEndPoint;
        private EndPoint mIPEndPoint;
        private KCP mKcp;
        private bool mNeedUpdateFlag;
        private UInt32 mNextUpdateTime;
        private byte[] mRecvBuffer;
        public delegate void OnRevDataDelegate(LuaByteBuffer data);
        public OnRevDataDelegate OnRevData;
        uint CurrentTime;

        public void Connect(string host, UInt16 port, UInt32 conv)
        {
            Close();
            CurrentTime = 0;
            IPAddress address = IPAddress.Parse(host);
            mSvrEndPoint = new IPEndPoint(address, port);
            mIPEndPoint = new IPEndPoint(address, port);
            mUdpClient = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            mUdpClient.Blocking = false;
            init_kcp(conv);
            mRecvBuffer = new byte[mKcp.GetMtu()];
        }

        void init_kcp(UInt32 conv)
        {
            mKcp = new KCP(conv, (byte[] buf, int size) =>
            {
                mUdpClient.SendTo(buf, size, SocketFlags.None, mSvrEndPoint);
            });

            // fast mode.
            mKcp.NoDelay(1, 10, 2, 1);
            mKcp.WndSize(128, 128);
        }

        public void Close()
        {
            mUdpClient = null;
            mKcp = null;
        }

        public void Send(byte[] _data)
        {
            if (_data == null)
                _data = new byte[0];
            mKcp.Send(_data);
            mNeedUpdateFlag = true;
        }

        public void Tick(float deltaTime)
        {
            if (mUdpClient == null || mKcp == null) return;

            CurrentTime = CurrentTime + (uint)(1000 * deltaTime);
            process_recv_queue();
            if (mNeedUpdateFlag || CurrentTime >= mNextUpdateTime)
            {
                mKcp.Update(CurrentTime);
                mNextUpdateTime = mKcp.Check(CurrentTime);
                mNeedUpdateFlag = false;
            }
        }

        void process_recv_queue()
        {
            //从网络读
            int len = 0;
            try
            {
                do
                {
                    len = mUdpClient.ReceiveFrom(mRecvBuffer, ref mIPEndPoint);
                    if (len > 0)
                    {
                        uint conv = 0;
                        KCP.ikcp_decode32u(mRecvBuffer, 0, ref conv);
                        byte[] data = new byte[len];
                        Array.Copy(mRecvBuffer, data, len);
                        mKcp.Input(data);
                        mNeedUpdateFlag = true;
                    }
                }
                while (len > 0);
            }
            catch (SocketException e){ }

            //从kcp读
            int packetSize = 0;
            while ((packetSize = mKcp.PeekSize()) > 0)
            {
                var data = new byte[packetSize];
                mKcp.Recv(data);
                if (OnRevData != null)
                {
                    OnRevData(new LuaByteBuffer(data));
                }
            }
        }
    }
}